added samples
[windows-sources.git] / sdk / samples / all in on code / Visual Studio 2008 / CSWindowsHook / MainForm.cs
blob0b1820a20bd67bc726d8d9011ee35cd7a9f530f2
1 /******************************** Module Header *********************************\
2 * Module Name: MainForm.cs
3 * Project: CSWindowsHook
4 * Copyright (c) Microsoft Corporation.
5 *
6 * This example demonstrates how to set a hook that is specific to a thread as well
7 * as the global hook by using the low-level mouse and keyboard hooks in .NET. You
8 * can use hooks to monitor certain types of events. You can associate these events
9 * with a specific thread or with all the threads in the same desktop as the
10 * calling thread.
12 * This source is subject to the Microsoft Public License.
13 * See http://www.microsoft.com/opensource/licenses.mspx#Ms-PL.
14 * All other rights reserved.
16 * History:
17 * * 3/28/2009 11:04 PM Rongchun Zhang Created
18 * * 4/6/2009 1:26 PM Jialiang Ge Reviewed
19 \********************************************************************************/
21 #region Using directives
22 using System;
23 using System.Collections.Generic;
24 using System.ComponentModel;
25 using System.Data;
26 using System.Drawing;
27 using System.Text;
28 using System.Windows.Forms;
29 using System.Runtime.InteropServices;
30 using System.Threading;
31 using System.Reflection;
32 using System.Diagnostics;
33 #endregion
36 namespace CSWindowsHook
38 public partial class MainForm : Form
40 public MainForm()
42 InitializeComponent();
45 private const int WM_KEYDOWN = 0x100;
46 private const int WM_SYSKEYDOWN = 0x104;
49 #region Local Mouse Hook
51 // Handle to the local mouse hook procedure
52 private IntPtr hLocalMouseHook = IntPtr.Zero;
53 private HookProc localMouseHookCallback = null;
55 /// <summary>
56 /// Set local mouse hook
57 /// </summary>
58 /// <returns></returns>
59 private bool SetLocalMouseHook()
61 // Create an instance of HookProc.
62 localMouseHookCallback = new HookProc(this.MouseProc);
64 hLocalMouseHook = NativeMethods.SetWindowsHookEx(
65 HookType.WH_MOUSE,
66 localMouseHookCallback,
67 IntPtr.Zero,
68 NativeMethod.GetCurrentThreadId());
69 return hLocalMouseHook != IntPtr.Zero;
72 /// <summary>
73 /// Remove the local mouse hook
74 /// </summary>
75 /// <returns></returns>
76 private bool RemoveLocalMouseHook()
78 if (hLocalMouseHook != IntPtr.Zero)
80 // Unhook the mouse hook
81 if (!NativeMethods.UnhookWindowsHookEx(hLocalMouseHook))
82 return false;
84 hLocalMouseHook = IntPtr.Zero;
86 return true;
89 /// <summary>
90 /// Mouse hook procedure
91 /// The system calls this function whenever an application calls the
92 /// GetMessage or PeekMessage function and there is a mouse message to be
93 /// processed.
94 /// </summary>
95 /// <param name="nCode">
96 /// The hook code passed to the current hook procedure.
97 /// When nCode equals HC_ACTION, the wParam and lParam parameters contain
98 /// information about a mouse message.
99 /// When nCode equals HC_NOREMOVE, the wParam and lParam parameters
100 /// contain information about a mouse message, and the mouse message has
101 /// not been removed from the message queue. (An application called the
102 /// PeekMessage function, specifying the PM_NOREMOVE flag.)
103 /// </param>
104 /// <param name="wParam">
105 /// Specifies the identifier of the mouse message.
106 /// </param>
107 /// <param name="lParam">Pointer to a MOUSEHOOKSTRUCT structure.</param>
108 /// <returns></returns>
109 /// <see cref="http://msdn.microsoft.com/en-us/library/ms644988.aspx"/>
110 private int MouseProc(int nCode, IntPtr wParam, IntPtr lParam)
112 if (nCode == HookCodes.HC_ACTION)
114 // Marshal the MOUSEHOOKSTRUCT data from the callback lParam
115 MOUSEHOOKSTRUCT mouseHookStruct = (MOUSEHOOKSTRUCT)
116 Marshal.PtrToStructure(lParam, typeof(MOUSEHOOKSTRUCT));
118 // Get the mouse WM from the wParam parameter
119 MouseMessage wmMouse = (MouseMessage)wParam;
121 // Display the current mouse coordinates and the message
122 String log = String.Format("X = {0} Y = {1} ({2})\r\n",
123 mouseHookStruct.pt.x, mouseHookStruct.pt.y, wmMouse);
124 this.tbLog.AppendText(log);
127 // Pass the hook information to the next hook procedure in chain
128 return NativeMethods.CallNextHookEx(hLocalMouseHook, nCode, wParam, lParam);
131 #endregion
134 #region Global Low-level Mouse Hook
136 // Handle to the global low-level mouse hook procedure
137 private IntPtr hGlobalLLMouseHook = IntPtr.Zero;
138 private HookProc globalLLMouseHookCallback = null;
140 /// <summary>
141 /// Set global low-level mouse hook
142 /// </summary>
143 /// <returns></returns>
144 private bool SetGlobalLLMouseHook()
146 // Create an instance of HookProc.
147 globalLLMouseHookCallback = new HookProc(this.LowLevelMouseProc);
149 hGlobalLLMouseHook = NativeMethods.SetWindowsHookEx(
150 HookType.WH_MOUSE_LL, // Must be LL for the global hook
151 globalLLMouseHookCallback,
152 // Get the handle of the current module
153 Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]),
154 // The hook procedure is associated with all existing threads running
155 // in the same desktop as the calling thread.
157 return hGlobalLLMouseHook != IntPtr.Zero;
160 /// <summary>
161 /// Remove the global low-level mouse hook
162 /// </summary>
163 /// <returns></returns>
164 private bool RemoveGlobalLLMouseHook()
166 if (hGlobalLLMouseHook != IntPtr.Zero)
168 // Unhook the low-level mouse hook
169 if (!NativeMethods.UnhookWindowsHookEx(hGlobalLLMouseHook))
170 return false;
172 hGlobalLLMouseHook = IntPtr.Zero;
174 return true;
177 /// <summary>
178 /// Low-level mouse hook procedure
179 /// The system call this function every time a new mouse input event is
180 /// about to be posted into a thread input queue. The mouse input can come
181 /// from the local mouse driver or from calls to the mouse_event function.
182 /// If the input comes from a call to mouse_event, the input was
183 /// "injected". However, the WH_MOUSE_LL hook is not injected into another
184 /// process. Instead, the context switches back to the process that
185 /// installed the hook and it is called in its original context. Then the
186 /// context switches back to the application that generated the event.
187 /// </summary>
188 /// <param name="nCode">
189 /// The hook code passed to the current hook procedure.
190 /// When nCode equals HC_ACTION, the wParam and lParam parameters contain
191 /// information about a mouse message.
192 /// </param>
193 /// <param name="wParam">
194 /// This parameter can be one of the following messages:
195 /// WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MOUSEMOVE, WM_MOUSEWHEEL,
196 /// WM_MOUSEHWHEEL, WM_RBUTTONDOWN, or WM_RBUTTONUP.
197 /// </param>
198 /// <param name="lParam">Pointer to an MSLLHOOKSTRUCT structure.</param>
199 /// <returns></returns>
200 /// <see cref="http://msdn.microsoft.com/en-us/library/ms644986.aspx"/>
201 public int LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam)
203 if (nCode >= 0)
205 // Marshal the MSLLHOOKSTRUCT data from the callback lParam
206 MSLLHOOKSTRUCT mouseLLHookStruct = (MSLLHOOKSTRUCT)
207 Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
209 // Get the mouse WM from the wParam parameter
210 MouseMessage wmMouse = (MouseMessage)wParam;
212 // Display the current mouse coordinates and the message
213 String log = String.Format("X = {0} Y = {1} ({2})\r\n",
214 mouseLLHookStruct.pt.x, mouseLLHookStruct.pt.y, wmMouse);
215 this.tbLog.AppendText(log);
218 // Pass the hook information to the next hook procedure in chain
219 return NativeMethods.CallNextHookEx(hGlobalLLMouseHook, nCode, wParam, lParam);
222 #endregion
225 #region Local Keyboard Hook
227 // Handle to the local keyboard hook procedure
228 private IntPtr hLocalKeyboardHook = IntPtr.Zero;
229 private HookProc localKeyboardHookCallback = null;
231 /// <summary>
232 /// Set local keyboard hook
233 /// </summary>
234 /// <returns></returns>
235 private bool SetLocalKeyboardHook()
237 // Create an instance of HookProc.
238 localKeyboardHookCallback = new HookProc(this.KeyboardProc);
240 hLocalKeyboardHook = NativeMethods.SetWindowsHookEx(
241 HookType.WH_KEYBOARD,
242 localKeyboardHookCallback,
243 IntPtr.Zero,
244 NativeMethod.GetCurrentThreadId());
245 return hLocalKeyboardHook != IntPtr.Zero;
248 /// <summary>
249 /// Remove the local keyboard hook
250 /// </summary>
251 /// <returns></returns>
252 private bool RemoveLocalKeyboardHook()
254 if (hLocalKeyboardHook != IntPtr.Zero)
256 // Unhook the mouse hook
257 if (!NativeMethods.UnhookWindowsHookEx(hLocalKeyboardHook))
258 return false;
260 hLocalKeyboardHook = IntPtr.Zero;
262 return true;
265 /// <summary>
266 /// Keyboard hook procedure
267 /// The system calls this function whenever an application calls the
268 /// GetMessage or PeekMessage function and there is a keyboard message
269 /// (WM_KEYUP or WM_KEYDOWN) to be processed.
270 /// </summary>
271 /// <param name="nCode">
272 /// The hook code passed to the current hook procedure.
273 /// When nCode equals HC_ACTION, the wParam and lParam parameters contain
274 /// information about a keystroke message.
275 /// When nCode equals HC_NOREMOVE, the wParam and lParam parameters
276 /// contain information about a keystroke message, and the keystroke
277 /// message has not been removed from the message queue. (An application
278 /// called the PeekMessage function, specifying the PM_NOREMOVE flag.)
279 /// </param>
280 /// <param name="wParam">
281 /// Specifies the virtual-key code of the key that generated the keystroke
282 /// message. http://msdn.microsoft.com/en-us/library/dd375731.aspx
283 /// </param>
284 /// <param name="lParam">
285 /// Specifies the repeat count, scan code, extended-key flag, context code,
286 /// previous key-state flag, and transition-state flag.
287 /// http://msdn.microsoft.com/en-us/library/ms646267.aspx#_win32_Keystroke_Message_Flags
288 /// </param>
289 /// <returns></returns>
290 /// <see cref="http://msdn.microsoft.com/en-us/library/ms644984.aspx"/>
291 public int KeyboardProc(int nCode, IntPtr wParam, IntPtr lParam)
293 if (nCode == HookCodes.HC_ACTION)
295 // Get the virtual key code from wParam
296 // http://msdn.microsoft.com/en-us/library/dd375731.aspx
297 Keys vkCode = (Keys)wParam;
299 // Get the keystroke message flags
300 // http://msdn.microsoft.com/en-us/library/ms646267.aspx#_win32_Keystroke_Message_Flags
301 string flag = lParam.ToString("X8");
303 string log = String.Format("Virtual-Key code: {0} Flag: {1}\r\n",
304 vkCode, flag);
305 this.tbLog.AppendText(log);
308 // Pass the hook information to the next hook procedure in chain
309 return NativeMethods.CallNextHookEx(hLocalKeyboardHook, nCode, wParam, lParam);
312 #endregion
315 #region Global Low-level Keyboard Hook
317 // Handle to the global low-level keyboard hook procedure
318 private IntPtr hGlobalLLKeyboardHook = IntPtr.Zero;
319 private HookProc globalLLKeyboardHookCallback = null;
321 /// <summary>
322 /// Set global low-level keyboard hook
323 /// </summary>
324 /// <returns></returns>
325 private bool SetGlobalLLKeyboardHook()
327 // Create an instance of HookProc.
328 globalLLKeyboardHookCallback = new HookProc(this.LowLevelKeyboardProc);
330 hGlobalLLKeyboardHook = NativeMethods.SetWindowsHookEx(
331 HookType.WH_KEYBOARD_LL, // Must be LL for the global hook
332 globalLLKeyboardHookCallback,
333 // Get the handle of the current module
334 Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]),
335 // The hook procedure is associated with all existing threads running
336 // in the same desktop as the calling thread.
338 return hGlobalLLKeyboardHook != IntPtr.Zero;
341 /// <summary>
342 /// Remove the global low-level keyboard hook
343 /// </summary>
344 /// <returns></returns>
345 private bool RemoveGlobalLLKeyboardHook()
347 if (hGlobalLLKeyboardHook != IntPtr.Zero)
349 // Unhook the mouse hook
350 if (!NativeMethods.UnhookWindowsHookEx(hGlobalLLKeyboardHook))
351 return false;
353 hGlobalLLKeyboardHook = IntPtr.Zero;
355 return true;
358 /// <summary>
359 /// Low-level keyboard hook procedure.
360 /// The system calls this function every time a new keyboard input event
361 /// is about to be posted into a thread input queue. The keyboard input
362 /// can come from the local keyboard driver or from calls to the
363 /// keybd_event function. If the input comes from a call to keybd_event,
364 /// the input was "injected". However, the WH_KEYBOARD_LL hook is not
365 /// injected into another process. Instead, the context switches back
366 /// to the process that installed the hook and it is called in its
367 /// original context. Then the context switches back to the application
368 /// that generated the event.
369 /// </summary>
370 /// <param name="nCode">
371 /// The hook code passed to the current hook procedure.
372 /// When nCode equals HC_ACTION, it means that the wParam and lParam
373 /// parameters contain information about a keyboard message.
374 /// </param>
375 /// <param name="wParam">
376 /// The parameter can be one of the following messages:
377 /// WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, or WM_SYSKEYUP.
378 /// </param>
379 /// <param name="lParam">Pointer to a KBDLLHOOKSTRUCT structure.</param>
380 /// <returns></returns>
381 /// <see cref="http://msdn.microsoft.com/en-us/library/ms644985.aspx"/>
382 public int LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam)
384 if (nCode >= 0)
386 // Marshal the KeyboardHookStruct data from the callback lParam
387 KBDLLHOOKSTRUCT keyboardLLHookStruct = (KBDLLHOOKSTRUCT)
388 Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
390 // Get the virtual key code from KBDLLHOOKSTRUCT.vkCode
391 // http://msdn.microsoft.com/en-us/library/dd375731.aspx
392 Keys vkCode = (Keys)keyboardLLHookStruct.vkCode;
394 // Get the keyboard WM from the wParam parameter
395 KeyboardMessage wmKeyboard = (KeyboardMessage)wParam;
397 // Display the current mouse coordinates and the message
398 String log = String.Format("Virtual-Key code: {0} ({1})\r\n",
399 vkCode, wmKeyboard);
400 this.tbLog.AppendText(log);
403 // Pass the hook information to the next hook procedure in chain
404 return NativeMethods.CallNextHookEx(hGlobalLLKeyboardHook, nCode, wParam, lParam);
407 #endregion
410 #region Form Event Handlers
412 private void btnLocalMouseHook_Click(object sender, EventArgs e)
414 if (hLocalMouseHook == IntPtr.Zero)
416 // Set the local mouse hook
417 if (SetLocalMouseHook())
419 btnLocalMouseHook.Text = "Unhook Local Mouse Hook";
420 btnGlobalLLMouseHook.Enabled = false;
422 else
424 MessageBox.Show("SetWindowsHookEx(Mouse) failed");
427 else
429 // Remove the local mouse hook
430 if (RemoveLocalMouseHook())
432 btnLocalMouseHook.Text = "Set Local Mouse Hook";
433 btnGlobalLLMouseHook.Enabled = true;
435 else
437 MessageBox.Show("UnhookWindowsHookEx(Mouse) failed");
442 private void btnGlobalLLMouseHook_Click(object sender, EventArgs e)
444 if (hGlobalLLMouseHook == IntPtr.Zero)
446 // Set the global low-level mouse hook
447 if (SetGlobalLLMouseHook())
449 btnGlobalLLMouseHook.Text = "Unhook Global LL Mouse Hook";
450 btnLocalMouseHook.Enabled = false;
452 else
454 MessageBox.Show("SetWindowsHookEx(LL Mouse) failed");
457 else
459 // Remove the global low-level mouse hook
460 if (RemoveGlobalLLMouseHook())
462 btnGlobalLLMouseHook.Text = "Set Global LL Mouse Hook";
463 btnLocalMouseHook.Enabled = true;
465 else
467 MessageBox.Show("UnhookWindowsHookEx(LL Mouse) failed");
472 private void btnLocalKeyboardHook_Click(object sender, EventArgs e)
474 if (hLocalKeyboardHook == IntPtr.Zero)
476 // Set the local keyboard hook
477 if (SetLocalKeyboardHook())
479 btnLocalKeyboardHook.Text = "Unhook Local Keyboard Hook";
480 btnGlobalLLKeyboardHook.Enabled = false;
482 else
484 MessageBox.Show("SetWindowsHookEx(Keyboard) failed");
487 else
489 // Remove the local keyboard hook
490 if (RemoveLocalKeyboardHook())
492 btnLocalKeyboardHook.Text = "Set Local Keyboard Hook";
493 btnGlobalLLKeyboardHook.Enabled = true;
495 else
497 MessageBox.Show("UnhookWindowsHookEx(Keyboard) failed");
502 private void btnGlobalLLKeyboardHook_Click(object sender, EventArgs e)
504 if (hGlobalLLKeyboardHook == IntPtr.Zero)
506 // Set the global low-level keyboard hook
507 if (SetGlobalLLKeyboardHook())
509 btnGlobalLLKeyboardHook.Text = "Unhook Global LL Keyboard Hook";
510 btnLocalKeyboardHook.Enabled = false;
512 else
514 MessageBox.Show("SetWindowsHookEx(LL KeyBoard) failed");
517 else
519 // Remove the global low-level keyboard hook
520 if (RemoveGlobalLLKeyboardHook())
522 btnGlobalLLKeyboardHook.Text = "Set Global LL Keyboard Hook";
523 btnLocalKeyboardHook.Enabled = true;
525 else
527 MessageBox.Show("UnhookWindowsHookEx(LL Keyboard) failed");
532 /// <summary>
533 /// Remove all hooks if set when closing form
534 /// </summary>
535 /// <param name="sender"></param>
536 /// <param name="e"></param>
537 private void FrmMain_FormClosing(object sender, FormClosingEventArgs e)
539 RemoveLocalMouseHook();
540 RemoveGlobalLLMouseHook();
541 RemoveLocalKeyboardHook();
542 RemoveGlobalLLKeyboardHook();
545 #endregion